package com.learn.concurrent;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * @author wangxing
 * @version 2020/8/5 21:28 Administrator
 */
public class LearnJMM {
    Logger logger = LoggerFactory.getLogger(LearnJMM.class);
    public static void main(String[] args) throws Exception {
        LearnJMM learnJMM = new LearnJMM();
//        learnJMM.threadTagAndSeek();
//        learnJMM.threadWhileCanNotQuit();
        learnJMM.threadWhileCanNotQuit1();
//        learnJMM.threadWhileCanQuit1();
//        learnJMM.threadWhileCanQuit2();
    }


    static boolean flag = false;
    /**
     * 执行后不能退出,因为线程间不能相互读取数据,根据JMM
     */
    public void threadWhileCanNotQuit() {
        Thread threadA = new Thread(() -> {
            System.out.println("开始执行A");
            while (!flag) {
            }
            System.out.println(" 读取到 flag ");
        }, "threadA");
        threadA.start();
        try {
            Thread.sleep(10000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        Thread threadB = new Thread(() -> {
            System.out.println("执行了线程B");
            flag = true;
            System.out.println("更新flag");
        }, "threadB");
        threadB.start();
    }
    static int count = 0;
    /**
     * 执行后不能退出,因为线程间不能相互读取数据,根据JMM
     */
    public void threadWhileCanNotQuit1() {
        Thread threadA = new Thread(() -> {
            System.out.println("开始执行A");
            while (!flag) {
                count++;
            }
            System.out.println(" 读取到 flag ");
        }, "threadA");
        threadA.start();
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        Thread threadB = new Thread(() -> {
            System.out.println("执行了线程B");
            flag = true;
            System.out.println("更新flag");
        }, "threadB");
        threadB.start();
    }
    static Integer c =0;
    /**
     * 执行后能退出,因为出现CPU时间片切换,导致线程A去主内存中重新获取数据
     */
    public void threadWhileCanQuit1() {
        Thread threadA = new Thread(() -> {
            System.out.println("开始执行A");
            while (!flag) {
                if(c<100000){
                    c++;
                }
            }
            System.out.println(" 读取到 flag ");
        }, "threadA");
        threadA.start();
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        Thread threadB = new Thread(() -> {
            System.out.println("执行了线程B");
            flag = true;
            System.out.println("更新flag");
        }, "threadB");
        threadB.start();
    }

    static volatile int count2 = 0;
    /**
     * 执行后不能退出,因为 count2为volatile更新后将重新获取内存区域数据,在内存区内将flag也重新获取了
     */
    public void threadWhileCanQuit2() {
        Thread threadA = new Thread(() -> {
            System.out.println("开始执行A");
            while (!flag) {
                count2++;
            }
            System.out.println(" 读取到 flag ");
        }, "threadA");
        threadA.start();
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        Thread threadB = new Thread(() -> {
            System.out.println("执行了线程B");
            flag = true;
            System.out.println("更新flag");
        }, "threadB");
        threadB.start();
    }

    static int a, b, x, y = 0;
    /**
     * 指令重排的验证
     */
    public void threadTagAndSeek() throws InterruptedException {
        int i = 0;
        while (true) {
            a = b = x = y = 0;
            Thread t1 = new Thread(() -> {
                a = 1;
                x = b;
            });
            Thread t2 = new Thread(() -> {
                b = 1;
                y = a;
            });
            t1.start();
            t2.start();
            t1.join();
            t2.join();
            i++;
            if(x==0 && y==0){
                logger.info("执行第{}次 , x = {}; y = {}", i,x,y);
                break;
            }else{
                logger.info("执行第{}次 , x = {}; y = {}", i,x,y);
            }
        }
    }
}
